//
// Created by Suzhen on 2017/1/5.
//

#include "HttpRequest.h"
#include "boost/format.hpp"

USING_ORION_V2

int HttpRequest::OnMessageBegin(http_parser *pser) {
    HttpRequest *req = static_cast<HttpRequest *>( pser->data);
    req->currentStatus_ = MSG_BEGIN;
    return 0;
}

int HttpRequest::OnUrl(http_parser *pser, const char *at, size_t length) {
    HttpRequest *req = static_cast<HttpRequest *>( pser->data);
    req->currentStatus_ = MSG_URL;
    req->url_ = std::string(at, length);
    return 0;
}

int HttpRequest::OnHeaderField(http_parser *pser, const char *at, size_t length) {
    HttpRequest *req = static_cast<HttpRequest *>( pser->data);
    req->tempHeaderKey_ = std::string(at, length);
    return 0;
}

int HttpRequest::OnHeaderValue(http_parser *pser, const char *at, size_t length) {
    HttpRequest *req = static_cast<HttpRequest *>( pser->data);
    req->headers_.emplace(req->tempHeaderKey_, std::string(at, length));
    return 0;
}

int HttpRequest::OnHeaderComplete(http_parser *pser) {
    HttpRequest *req = static_cast<HttpRequest *>( pser->data);
    req->currentStatus_ = MSG_HEADER;
    return 0;
}

int HttpRequest::OnBody(http_parser *pser, const char *at, size_t length) {
    HttpRequest *req = static_cast<HttpRequest *>( pser->data);
#ifdef ENABLE_LOG
    LOG_I << "OnBody " << std::string(at, length) << " length -> " << length;
#endif
    req->contentBodyStream_ << std::string(at, length);
    req->currentStatus_ = MSG_BODY;
    return 0;
}

int HttpRequest::OnMessageComplete(http_parser *pser) {
    HttpRequest *req = static_cast<HttpRequest *>( pser->data);
    req->currentStatus_ = MSG_END;
    return 0;
}

HttpRequest::~HttpRequest() {
#ifdef ENABLE_LOG
    LOG_I << "dispose HttpRequest";
#endif
}

HttpRequest::HttpRequest() {
#ifdef ENABLE_LOG
    LOG_I << "new HttpRequest";
#endif
    parseType_ = http_parser_type::HTTP_REQUEST;
    http_parser_settings_init(&settings_);
    settings_.on_message_begin = OnMessageBegin;
    settings_.on_url = OnUrl;
    settings_.on_header_field = OnHeaderField;
    settings_.on_header_value = OnHeaderValue;
    settings_.on_headers_complete = OnHeaderComplete;
    settings_.on_body = OnBody;
    settings_.on_message_complete = OnMessageComplete;
    http_parser_init(&parser_, parseType_);
    parser_.data = this;
}

void HttpRequest::executeParse(const char *data, size_t dataLen) {
    if (currentStatus_ == MSG_BREAK) {
        return;
    }
    size_t parseLen = http_parser_execute(&parser_, &settings_, data, dataLen);
    if (parseLen != dataLen) {
        if (parser_.http_errno != HPE_OK) {
            currentStatus_ = MSG_BREAK;
        }
    }
}

void HttpRequest::printDetails() {
    CHECK(currentStatus_ == MSG_END) << "bad request,unable to print";
    LOG_I << "http method -> " << http_method_str((http_method) parser_.method);
    std::for_each(headers_.begin(), headers_.end(),
                  [](std::pair<const std::string, std::string> &itm) {
                      LOG_I << "header field -> " << itm.first << " , value -> " << itm.second;
                  });
    LOG_I << "http body -> " << getBody();
}

const std::string &HttpRequest::getUrl() const {
    return url_;
}

const std::map<std::string, std::string> &HttpRequest::getHeaders() const {
    return headers_;
}

std::string HttpRequest::getBody() const {
    return contentBodyStream_.str();
}

bool HttpRequest::hasErr() const {
    return currentStatus_ == MSG_BREAK;
}

bool HttpRequest::hasDone() const {
    return currentStatus_ == MSG_END;
}
